Physics: a renderable that places itself collides at its pos - #1694
Merged
Merged
Conversation
20.7 moved every backend onto the frame a renderable DRAWS in, subtracting `size * anchorPoint` from where a body is built. That assumed every renderable takes that offset, and the engine already has a flag saying otherwise: `applyAnchorTransform`, which is what `preDraw` reads before shifting anything. `GLTFModel` clears it in its constructor and `Mesh` clears it on the `Camera3d` world-space path, because both emit world coordinates and pivot about their own model origin rather than a bounds box, so they draw at `pos` while their `anchorPoint` still holds the default (0.5, 0.5), where it means nothing. Reading it anyway moved each of those bodies by half its OWN bounds box. A scene sizes that box per node, so two objects overlapping on screen were displaced by different amounts and the contact between them was not merely shifted, it was never reported at all. The same condition now guards all five places that compute the offset: the 2D and 3D narrowphases, the builtin adapter's geometry readback, and both external adapters, which see this through any ordinary `Rect` on such a renderable and not only through a `Box3d`. `raycast3d` is fixed with it. 20.7 moved the narrowphase onto the drawn frame and left `raycast3d` building its world AABB from raw `pos`, so a floor probe and the solver disagreed by half a renderable on any anchored body. Nothing caught that because no test compared the two, which is what the new case in `raycast3d-box3d.spec.js` does. Six regression tests, each verified to fail with the defect put back. `matter-adapter` 1.5.1 and `planck-adapter` 1.6.1, since 1.5.0 and 1.6.0 went to npm carrying this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NGvtaUNATVCVxD2qcbiY4t
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #1693, which shipped a hole in its own fix, and a second defect it left behind.
A renderable that places itself
#1693 moved every backend onto the frame a renderable DRAWS in, subtracting
size * anchorPointfrom where a body is built. That assumed every renderable takes that offset, and the engine already carries a flag saying otherwise:applyAnchorTransform, which is whatpreDrawreads before shifting anything.GLTFModelclears it in its constructor,Meshclears it on theCamera3dworld-space path, both because they emit world coordinates and pivot about their own model origin rather than a bounds box. They draw atposwhile theiranchorPointstill holds the default(0.5, 0.5), where it means nothing.Reading it anyway moved each of those bodies by half its OWN bounds box. A scene sizes that box per node, so two objects that overlap on screen were displaced by different amounts, and the contact between them was not merely shifted, it was never reported at all. The Jungle Rabbit example is built entirely from such renderables and lost its collisions completely.
The same condition now guards all five places that compute the offset:
sat.jssat3d.jsBox3dnarrowphasebuiltin-adapter.tsgetBodyShapes/getBodyAABB/raycast3dmatter-adapter/src/index.tsplanck-adapter/src/index.tsThe two external adapters are in scope despite never seeing a
Box3d: the flag is a plainRenderableflag, so an ordinaryRecthitbox on such a renderable was mis-built there too. The parity case added to both is exactly that, and it fails on both without the fix.raycast3dmeasured in a different frame#1693 moved the narrowphase onto the drawn frame and left
raycast3dbuilding its world AABB from rawpos. For any anchored body the two then disagreed by half a renderable, so a floor probe placed a character on a surface the solver does not have there. Nothing failed, because every existing case in that spec was one body queried against itself and no test compared the query to the narrowphase.raycast3d-box3d.spec.jsnow authors in the collision frame and has a case pinning the two together.Tests
Six new cases, each verified to fail with the defect put back:
box3d-world.spec.js— a renderable that places itself collides where it draws, and one that does not still reads its anchor (mutants in both directions killed)builtin-resting.spec.js— the same contract through a full 2D dropraycast3d-box3d.spec.js— a ray hits the box where the narrowphase collides with itparity.spec.tson both adapters — aRectbody on a renderable that places itselfThe first draft of the
Box3dpair was vacuous: sizing each box from its own renderable's bounds made the anchor shift scale with the box, so the contact survived it. The boxes are now sized independently of the bounds they hang off.melonjs: 7148 passed. matter: 225. planck: 220. debug-plugin: 23.
Releases
@melonjs/matter-adapter1.5.1 and@melonjs/planck-adapter1.6.1, dated and ready to dispatch on merge, since 1.5.0 and 1.6.0 went to npm carrying this. melonjs 20.7.0 stays_unreleased_; its entry is amended rather than added to, since the hole never shipped there.🤖 Generated with Claude Code
https://claude.ai/code/session_01NGvtaUNATVCVxD2qcbiY4t